package cn.edu.nju.ws.sview.wyge.relations.adataset.relations.qxliu.relation;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashSet;

import com.hp.hpl.jena.vocabulary.RDF;
import com.mysql.jdbc.jdbc2.optional.SuspendableXAConnection;

import cn.edu.nju.ws.sview.cache.URIIDCache;
import cn.edu.nju.ws.sview.database.DBConnectionFactory;
import cn.edu.nju.ws.sview.rdf.RDFDocument;
import cn.edu.nju.ws.sview.rdf.Resource;
import cn.edu.nju.ws.sview.rdf.ResourceFactory;
import cn.edu.nju.ws.sview.rdf.URIResource;
import cn.edu.nju.ws.sview.reasoning.Atom;
import cn.edu.nju.ws.sview.reasoning.Constant;
import cn.edu.nju.ws.sview.reasoning.GroundAtom;
import cn.edu.nju.ws.sview.reasoning.KnowledgeBase;
import cn.edu.nju.ws.sview.reasoning.Predicate;
import cn.edu.nju.ws.sview.reasoning.Rule;
import cn.edu.nju.ws.sview.reasoning.Term;
import cn.edu.nju.ws.sview.reasoning.Variable;
import cn.edu.nju.ws.sview.reasoning.provenance.Provenance;
import cn.edu.nju.ws.sview.reasoning.provenance.ProvenanceFactory;

public class RelationEvaluation {
	private int relation_id = -1;
	// private String ds_type = null;
	// private String name = null;
	// private int ds_id = -1;
	private ArrayList<Integer> doc_id = null;
	private ArrayList<String[]> re_pattern = null;// s,p,o
	// private HashSet<GroundAtom> values = null;
	private ArrayList<ArrayList<String>> values = null;
	// private Connection conn = null;
	public static int TYPE_ID;// uri_id of rdf_type

	public RelationEvaluation() {
		int typeid = 0;
		try {
			typeid = URIIDCache.getInstance().getURIID(
					"http://www.w3.org/1999/02/22-rdf-syntax-ns#type", false);
		} catch (Throwable e1) {
			// TODO Auto-generated catch block
			e1.printStackTrace();
		}
		TYPE_ID = typeid;
	}

	public static void main(String[] args) {
		ArrayList<Integer> d = new ArrayList<Integer>();
//		d.add(10849110);//(181903600);// (29696112);
		// //// Relation rel = new Relation(1,d);
		// //// d.add(181903600);
		// RelationEvaluation rel = new RelationEvaluation();
		// System.out.println(rel.getValuesFromDocs(3,d).toString());
		// // rel.close();
		//

		ArrayList<String[]> patterns = new ArrayList<String[]>();
		// patterns.add(new
		// String[]{"v1","uhttp://www.w3.org/2000/01/rdf-schema#label","v2"});//(new
		// String[]{"v1","http://www.w3.org/2000/01/rdf-schema#subClassOf","v2"});
//		patterns.add(new String[] { "v1",
//				"uhttp://www.w3.org/2000/01/rdf-schema#label", "v2" });// (new
																		// String[]{"v1","uhttp://xmlns.com/foaf/0.1/knows","v2"});//
//		patterns.add(new String[] { "v1",
//				"uhttp://www.w3.org/1999/02/22-rdf-syntax-ns#type", "v3" });
//		patterns.add(new String[] { "v1",
//				"uhttp://www.w3.org/1999/02/22-rdf-syntax-ns#type", "v2" });
		patterns.add(new String[]{"v1","uhttp://www.w3.org/2000/01/rdf-schema#domain","v2"});//(new String[]{"v1","uhttp://purl.org/dc/elements/1.1/creator","v2"});//(new String[]{"v1","uhttp://www.w3.org/2000/01/rdf-schema#label","v2"});//(new String[]{"v1","uhttp://xmlns.com/foaf/0.1/knows","v2"});//
		patterns.add(new String[]{"v1","uhttp://www.w3.org/2000/01/rdf-schema#range","uhttp://www.w3.org/2002/07/owl#Thing"});
		d.add(477821);//(10849124);//(10849110);//(181903600);//(30900);//(4860);//(322960);//(38470);//
		
		RelationEvaluation rel = new RelationEvaluation();
		System.out.println(rel.getValuesFromPatterns(patterns, d));
		// rel.close();
	}

	/*
	 * public Relation(int relation_id, ArrayList<Integer> doc_id){
	 * this.relation_id = relation_id; this.doc_id = doc_id; }
	 */
	// public void close(){
	// if(this.conn != null){
	// try {
	// this.conn.close();
	// } catch (SQLException e) {
	// // TODO Auto-generated catch block
	// e.printStackTrace();
	// }
	// }
	// }
	public ArrayList<ArrayList<String>> getValuesFromPatterns(
			ArrayList<String[]> patterns, ArrayList<Integer> doc_id) {
		this.doc_id = doc_id;
		ArrayList<String[]> clone = (ArrayList<String[]>) patterns.clone();
		this.re_pattern = clone;
		return this.getValues();
	}

	public ArrayList<ArrayList<String>> getValuesFromDocs(int relation_id,
			ArrayList<Integer> doc_id) {
		this.relation_id = relation_id;
		this.doc_id = doc_id;
		if (this.re_pattern == null) {
			this.getPatterns();
		}
		return this.getValues();
	}

	private ArrayList<ArrayList<String>> getValues() {
		if (this.values == null) {
			/*
			 * if(this.re_pattern == null){ this.getPatterns(); }
			 */
			// if(this.conn == null){
			// conn = DBConnectionFactory.getConnection();
			// }
			// PreparedStatement pstmt;
			HashSet<GroundAtom> groundAtoms = null;
			ArrayList<Term> hterms = new ArrayList<Term>();
			try {
				// pstmt =
				// conn.prepareStatement("select uri from uri where id=?");
				Atom<Term> head = null;// new Atom<Term>(predicate, terms)
				ArrayList<Atom<Term>> body = new ArrayList<Atom<Term>>();
				Predicate pred = null;
				for (String[] pattern : this.re_pattern) {
					// System.out.println("pattern:\t"+pattern[0]+"\t"+pattern[1]+"\t"+pattern[2]);
					// Term s = getTerm(pattern[0],pstmt, null, null);
					String prop = pattern[1].substring(1);// remove prefix "u"

					Term s = getTerm(pattern[0], null, null, null);
					ArrayList<Term> terms = new ArrayList<Term>();
					if (s instanceof Variable && !hterms.contains(s)) {
						hterms.add(s);
					}
					// Term o = getTerm(pattern[2],pstmt, null, null);
					Term o = getTerm(pattern[2], null, null, null);
					Resource res_o = null;
					if (o instanceof Variable && !hterms.contains(o)) {
						hterms.add(o);
						// res_o =
						// ResourceFactory.getInstance().createTemporaryRDFResource();//====================
					} else if (o instanceof Constant) {
						res_o = ((Constant) o).getResource();
					}
					// if(RDF.type.getURI().equals(pattern[1])){
					if (RDF.type.getURI().equals(prop)) {
//						 System.out.println("typed:"+pattern[1]);
						if (res_o != null) {
							pred = new Predicate(res_o, 1);
							terms.add(s);
						} else {
							System.out.println("res_o is null error!");
						}
					} else {
						// pred = new
						// Predicate(ResourceFactory.getInstance().createURIResource(pattern[1]),2);
						pred = new Predicate(ResourceFactory.getInstance()
								.createURIResource(prop), 2);
						// System.out.println("not typed:"+pred.toString());
						terms.add(s);
						terms.add(o);
					}
					// System.out.println("terms:"+terms.toString());
					body.add(new Atom<Term>(pred, terms));
				}// end of for
				Resource res_h = ResourceFactory.getInstance()
						.createURIResource(
								ResourceFactory.INTERNAL_URI_PREFIX + "temp1");// ======name?
				head = new Atom<Term>(new Predicate(res_h, hterms.size()),
						hterms);
				// System.out.println("head:"+head.toString());

				Rule rule = new Rule(head, body, ProvenanceFactory
						.getInstance().createProvFromTemporary());
				// System.out.println("rule:"+rule);
				KnowledgeBase kb = new KnowledgeBase();
				kb.addRule(rule);

				this.addFactsToKb(kb);

//				 System.out.println("kb:"+kb.toString());
				groundAtoms = kb.Evaluate(head, false);
				// pstmt.close();
			} catch (SQLException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			if (groundAtoms != null) {
				this.values = new ArrayList<ArrayList<String>>();
				ArrayList<String> titles = new ArrayList<String>();
				for (Term t : hterms) {
					titles.add(t.toString().replace("?", ""));
					// titles.add(t.toString().replace("?", "v"));
				}
				this.values.add(titles);

				for (GroundAtom ga : groundAtoms) {
					ArrayList<String> item = new ArrayList<String>();
					ArrayList<Constant> cols = ga.getTerms();
					for (Constant con : cols) {
						String tmp = con.toString();
						tmp = tmp.startsWith("_") ? tmp : tmp.substring(
								1,
								tmp.contains("\"@") ? tmp.indexOf("\"@") : (tmp
										.length() - 1)).replace(">", "");//remove lang,type and <>
						item.add(tmp);
					}

					this.values.add(item);
				}
			}
		}
		return this.values;
	}

	private void addFactsToKb(KnowledgeBase kb) throws SQLException {
		// System.out.println("adding facts...");
		if (doc_id != null) {
			StringBuffer str_id = new StringBuffer();
			for (int id : doc_id) {
				str_id.append(id + ",");
			}
			if (str_id.length() > 0) {
				str_id.deleteCharAt(str_id.lastIndexOf(","));
			}
			Connection fconn = DBConnectionFactory.getConnection();// .getFalconConnection();
			// PreparedStatement pstmt =
			// fconn.prepareStatement("select s,p,o,c,lang from quadruple where c in ( "+str_id.toString()+" );");
			PreparedStatement pstmt = fconn
					.prepareStatement("select s,p,o,doc_id,lang from quadruple where doc_id in ( "
							+ str_id.toString() + " );");
			ResultSet rs = pstmt.executeQuery();
			PreparedStatement uri_pstmt = fconn
					.prepareStatement("select uri from uri where id=?");
			ResultSet uri_rs = null;
			while (rs.next()) {
				String doc_uri = null;
				uri_pstmt.setInt(1, Integer.valueOf(rs.getString(4)));
				uri_rs = uri_pstmt.executeQuery();
				if (uri_rs.next()) {
					doc_uri = uri_rs.getString(1);
				}
				RDFDocument rdfDoc = ResourceFactory.getInstance()
						.createRDFDocument(doc_uri);

				Predicate pred = null;
				ArrayList<Constant> terms = new ArrayList<Constant>();
				Constant ts = (Constant) this.getTerm(rs.getString(1),
						uri_pstmt, null, rdfDoc);
				Constant to = (Constant) this.getTerm(rs.getString(3),
						uri_pstmt, rs.getString(5), rdfDoc);
				Resource res_o = to.getResource();
				int typeid = 0;
				try {
					typeid = URIIDCache.getInstance().getURIID(
							"http://www.w3.org/1999/02/22-rdf-syntax-ns#type",
							false);
				} catch (Throwable e1) {
					// TODO Auto-generated catch block
					e1.printStackTrace();
				}

				if (rs.getString(2).contentEquals("u" + typeid)) {// if prop=rdf:type

					if (to != null) {
						pred = new Predicate(res_o, 1);
						terms.add(ts);
					}else{
						System.out.println("to is null error!");
					}
				} else {
					String uri_p = null;
					uri_pstmt.setInt(1,
							Integer.valueOf(rs.getString(2).substring(1)));
					uri_rs = uri_pstmt.executeQuery();
					if (uri_rs.next()) {
						uri_p = uri_rs.getString(1);
					}
					pred = new Predicate(ResourceFactory.getInstance()
							.createURIResource(uri_p), 2);
					terms.add(ts);
					terms.add(to);

					
				}
//				System.out.println("pred:"+pred.toString()+",\tterms:"+terms.toString());
				GroundAtom fact = new GroundAtom(pred, terms, ProvenanceFactory
						.getInstance().createProvFromRDFDocument(rdfDoc));
				kb.addFact(fact);
//				System.out.println("fa:"+fact.toString());
			}// end of while
			if (uri_rs != null) {
				uri_rs.close();
			}
			uri_pstmt.close();
			rs.close();
			pstmt.close();
			fconn.close();
		}// end of if

		// System.out.println("finished adding");
	}

	private Term getTerm(String str, PreparedStatement pstmt, String lang,
			RDFDocument rdfDoc) throws NumberFormatException, SQLException {
		Term t = null;
		ResultSet rs = null;
		if (str.startsWith("v")) {
			// t = new Variable(str.substring(1));
			t = new Variable(str);
		} else if (str.startsWith("uhttp://")) {
			t = new Constant(ResourceFactory.getInstance().createURIResource(
					str));
		} else if (str.startsWith("u")) {
			pstmt.setInt(1, Integer.valueOf(str.substring(1)));
			rs = pstmt.executeQuery();
			if (rs.next()) {
				t = new Constant(ResourceFactory.getInstance()
						.createURIResource("u" + rs.getString(1)));
			}
			// t = new
			// Constant(ResourceFactory.getInstance().createURIResource(str));
		} else if (str.startsWith("l")) {
			// t = new
			// Constant(ResourceFactory.getInstance().createPlainLiteral(str.substring(1),
			// lang));//========
			if (lang == null) {
				lang = "";// ==========================
			}
			t = new Constant(ResourceFactory.getInstance().createPlainLiteral(
					str, lang));
		} else if (rdfDoc != null && str.startsWith("b")) {
			// t = new
			// Constant(ResourceFactory.getInstance().createBlankNode(Integer.valueOf(str.substring(1)),
			// rdfDoc));
			int bid = str.contains(":") ? Integer.valueOf(str.substring(str
					.indexOf(":") + 1)) : Integer.valueOf(str.substring(1));
			t = new Constant(ResourceFactory.getInstance().createBlankNode(bid,
					rdfDoc));
//			System.out.println(bid + "\tblanknode:" + t.toString());
		} else {
			System.out.println("error1!");
		}
		// System.out.println("term:"+str+"\t"+t.toString());
		if (rs != null) {
			rs.close();
		}
		return t;
	}

	public ArrayList<String[]> getPatterns() {
		if (this.re_pattern == null) {
			// if(this.doc_id == null){
			// this.getDocId();
			// }
			Connection conn = DBConnectionFactory.getConnection();
			PreparedStatement pstmt;
			try {
				pstmt = conn
						.prepareStatement("select s,uri,o from re_pattern,uri where relation_id=? and uri.id=re_pattern.p");
				pstmt.setInt(1, this.relation_id);
				ResultSet rs = pstmt.executeQuery();
				this.re_pattern = new ArrayList<String[]>();
				String[] pitem = new String[3];
				while (rs.next()) {
					pitem[0] = rs.getString(1);
					pitem[1] = rs.getString(2);// uri of the predicate
					pitem[2] = rs.getString(3);
					// if(pitem[0].startsWith("v") || pitem[2].startsWith("v")){
					this.re_pattern.add(pitem);
					// }
				}
				rs.close();
				pstmt.close();
				conn.close();
			} catch (SQLException e) {
				e.printStackTrace();
			}
		}
		return this.re_pattern;
	}
	/*
	 * public ArrayList<Integer> getDocId(){ if(this.doc_id == null){
	 * if(this.ds_id < 0){ this.getDsId(); } if(this.conn == null){ conn =
	 * DBConnectionFactory.getConnection(); } try { PreparedStatement pstmt =
	 * conn
	 * .prepareStatement("select doc_id from custom_dataset_doc where dataset_id=?"
	 * ); pstmt.setInt(1, this.ds_id); ResultSet rs = pstmt.executeQuery();
	 * this.doc_id = new ArrayList<Integer>(); while(rs.next()){
	 * this.doc_id.add(rs.getInt(1)); } rs.close(); pstmt.close(); } catch
	 * (SQLException e) { // TODO Auto-generated catch block
	 * e.printStackTrace(); } } return this.doc_id; }
	 */
	/*
	 * public int getDsId(){ if(this.ds_id < 0){ if(this.conn == null){ conn =
	 * DBConnectionFactory.getConnection(); } PreparedStatement pstmt; try {
	 * pstmt =
	 * conn.prepareStatement("select ds_id from rs_ds where relation_id=?");
	 * pstmt.setInt(1, this.relation_id); ResultSet rs = pstmt.executeQuery();
	 * while(rs.next()){ this.ds_id = rs.getInt(1); } rs.close(); pstmt.close();
	 * } catch (SQLException e) { // TODO Auto-generated catch block
	 * e.printStackTrace(); } } return this.ds_id; }
	 */
}
